home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / NR3.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-19  |  24.9 KB  |  945 lines

  1. /* net/rom level 3 low level processing
  2.  * Dan Frank, W9NK
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "timer.h"
  10. #include "arp.h"
  11. #include "slip.h"
  12. #include "ax25.h"
  13. #include "netrom.h"
  14. #include "nr4.h"
  15. #include "lapb.h"
  16. #include <ctype.h>
  17.  
  18. extern int16 Axwindow ;
  19. struct ax25_cb *find_ax25(), *open_ax25() ;
  20. int psax25(), setpath() ;
  21. static struct nr_bind *find_best() ;
  22.  
  23. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  24. struct ax25_addr Nr_nodebc = {
  25.     'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  26.     ('0'<<1) | E
  27. } ;
  28.  
  29. struct nriface Nrifaces[NRNUMIFACE] ;
  30. unsigned Nr_numiface ;
  31. struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS] ;
  32. struct nrroute_tab *Nrroute_tab[NRNUMCHAINS] ;
  33. struct nrnf_tab *Nrnf_tab[NRNUMCHAINS] ;
  34. unsigned Nr_nfmode = NRNF_NOFILTER ;
  35. unsigned Nr_ttl = 64 ;
  36. unsigned Obso_init = 6 ;
  37. unsigned Obso_minbc = 5 ;
  38. unsigned Nr_maxroutes = 5 ;
  39. unsigned Nr_autofloor = 1 ;
  40. unsigned Nr_verbose = 0 ;
  41. struct iface *Nr_iface ;
  42.  
  43. /* send IP datagrams across a net/rom network connection */
  44. int
  45. nr_send(bp,iface,gateway,prec,del,tput,rel)
  46. struct mbuf *bp ;
  47. struct iface *iface ;
  48. int32 gateway ;
  49. int prec ;
  50. int del ;
  51. int tput ;
  52. int rel ;
  53. {
  54.     struct ax25_addr dest ;
  55.     struct mbuf *tbp, *pbp ;
  56.     struct nr3hdr n3hdr ;
  57.     struct nr4hdr n4hdr ;
  58.     char *hwaddr ;
  59.     struct arp_tab *arp ;
  60.  
  61.     if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  62.         free_p(bp) ;    /* drop the packet if no route */
  63.         return ;
  64.     }
  65.     hwaddr = arp->hw_addr ;                /* points to destination */
  66.     memcpy(dest.call, hwaddr, ALEN) ;
  67.     dest.ssid = hwaddr[ALEN] ;
  68.         
  69.     /* set up host format header */
  70.     /* We don't insert the source callsign here because */
  71.     /* we don't know the interface it's going to go out, and */
  72.     /* the interfaces might have different callsigns.       */
  73.     n3hdr.dest = dest ;
  74.     n3hdr.ttl = Nr_ttl ;
  75.  
  76.     /* Convert to a network format header.  This will be stripped */
  77.     /* back off in nr_route, but them's the breaks.               */
  78.     if ((tbp = htonnr3(&n3hdr)) == NULLBUF) {
  79.         free_p(bp) ;
  80.         return ;
  81.     }
  82.  
  83.     /* Add a "network extension" transport header */
  84.     n4hdr.opcode = NR4OPPID ;
  85.     n4hdr.u.pid.family = PID_IP ;
  86.     n4hdr.u.pid.proto = PID_IP ;
  87.  
  88.      if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
  89.          free_p(bp) ;
  90.          free_p(tbp) ;
  91.          return ;
  92.      }
  93.  
  94.      append(&tbp,pbp) ;        /* append pid info to network header ... */
  95.      append(&tbp,bp) ;        /* and append the data to that */
  96.      nr_route(tbp, NULLAX25) ; /* pass off to level 3 routing code */
  97.  
  98. }
  99.  
  100. /* Figure out if a call is assigned to one of my net/rom
  101.  * interfaces.
  102.  */
  103. static int
  104. ismycall(addr)
  105. struct ax25_addr *addr ;
  106. {
  107.     register int i ;
  108.     int found = 0 ;
  109.     
  110.     for (i = 0 ; i < Nr_numiface ; i++)
  111.         if (addreq((struct ax25_addr *)(Nrifaces[i].iface->hwaddr),
  112.             addr)) {
  113.             found = 1 ;
  114.             break ;
  115.         }
  116.  
  117.     return found ;
  118. }
  119.  
  120.  
  121. /* Route net/rom network layer packets.
  122.  */
  123. nr_route(bp, iaxp)
  124. struct mbuf *bp ;                /* network packet */
  125. struct ax25_cb *iaxp ;            /* incoming ax25 control block */
  126. {
  127.     struct nr3hdr n3hdr ;
  128.     struct nr4hdr n4hdr ;
  129.     struct ax25_cb *axp;
  130.     struct ax25 naxhdr ;
  131.     struct ax25_addr neighbor, from ;
  132.     struct mbuf *hbp, *pbp;
  133.     register struct nrnbr_tab *np ;
  134.     register struct nrroute_tab *rp ;
  135.     register struct nr_bind *bindp;
  136.     struct iface *iface ;
  137.     struct ax_route *axr ;
  138.     unsigned ifnum ;
  139.     
  140.     if (ntohnr3(&n3hdr,&bp) == -1) {
  141.         free_p(bp) ;
  142.         return ;
  143.     }
  144.  
  145.      /* If this isn't an internally generated network packet,
  146.       * give the router a chance to record a route back to the
  147.       * sender, in case they aren't in the local node's routing
  148.       * table yet.
  149.       */
  150.  
  151.      if (iaxp != NULLAX25) {
  152.         /* Find the interface in the routing table */
  153.         if ((axr = ax_lookup(&iaxp->remote)) == NULLAXR)
  154.             goto norecord ;    /* This "shouldn't happen" */
  155.             
  156.          /* find the interface number */
  157.          for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
  158.              if (iaxp->iface == Nrifaces[ifnum].iface)
  159.                  break ;
  160.  
  161.          if (ifnum == Nr_numiface) {    /* Not a net/rom interface! */
  162.              free_p(bp) ;
  163.              return ;
  164.          }
  165.  
  166.          from = iaxp->remote ;
  167.          from.ssid |= E ;
  168.  
  169.          /* Add (possibly) a zero-quality recorded route via */
  170.          /* the neighbor from which this packet was received */
  171.          /* Note that this doesn't work with digipeated neighbors. */
  172.          
  173.          (void) nr_routeadd("      ",&n3hdr.source,ifnum,0,
  174.                                      (char *)&from,0,1) ;
  175.     }
  176.  
  177. norecord:    /* If gotos are considered harmful, how about labels? */
  178.  
  179.      /* A packet from me, to me, can only be one thing: */
  180.      /* a horrible routing loop.  This will probably result */
  181.      /* from a bad manual ARP entry, but we should fix these */
  182.      /* obscure errors as we find them. */
  183.      
  184.       if (ismycall(&n3hdr.dest)) {
  185.           if (iaxp == NULLAX25) {        /* From me? */
  186.               free_p(bp) ;
  187.              return ;
  188.          } else {                    /* It's from somewhere else! */
  189.              if (ntohnr4(&n4hdr,&bp) == -1) {
  190.                  free_p(bp) ;
  191.                  return ;
  192.              }
  193.              if ((n4hdr.opcode & NR4OPCODE) == 0) {
  194.                  if (n4hdr.u.pid.family == PID_IP
  195.                      && n4hdr.u.pid.proto == PID_IP)
  196.                      ip_route(bp,0) ;
  197.                  else                     /* we don't do this proto */
  198.                      free_p(bp) ;
  199.  
  200.                  return ;
  201.              }
  202.              
  203.              /* Must be net/rom transport: */
  204.  
  205.              nr4input(&n4hdr,bp) ;
  206.  
  207.          }
  208.           return ;
  209.       }
  210.  
  211.     if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  212.         /* no route, drop the packet */
  213.         free_p(bp) ;
  214.         return ;
  215.     }
  216.  
  217.     if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  218.         /* This shouldn't happen yet, but might if we add */
  219.         /* dead route detection */
  220.         free_p(bp) ;
  221.         return ;
  222.     }
  223.  
  224.     np = bindp->via ;
  225.     memcpy(neighbor.call,np->call,ALEN) ;
  226.     neighbor.ssid = np->call[ALEN] ;
  227.     iface = Nrifaces[np->iface].iface ;
  228.  
  229.      /* Now check to see if iaxp is null.  That is */
  230.      /* a signal that the packet originates here, */
  231.       /* so we need to insert the callsign of the appropriate  */
  232.       /* interface */
  233.       if (iaxp == NULLAX25)
  234.         memcpy(&n3hdr.source,iface->hwaddr,AXALEN) ;
  235.     
  236.     /* Make sure there is a connection to the neighbor */
  237.     if ((axp = find_ax25(&neighbor)) == NULLAX25 || axp->state != CONNECTED) {
  238.         /* Open a new connection or reinitialize old one */
  239.         /* hwaddr has been advanced to point to neighbor + digis */
  240.         atohax25(&naxhdr, np->call, (struct ax25_addr *)iface->hwaddr) ;
  241.         axp = open_ax25(iface,&Mycall,&naxhdr.dest, Axwindow, NULLVFP, NULLVFP, NULLVFP,-1) ;
  242.         if (axp == NULLAX25) {
  243.             free_p(bp) ;
  244.             return ;
  245.         }
  246.     }
  247.         
  248.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  249.         free_p(bp) ;
  250.         return ;
  251.     }
  252.  
  253.     /* allocate and fill PID mbuf */
  254.     if ((pbp = alloc_mbuf(1)) == NULLBUF) {
  255.         free_p(bp) ;
  256.         return ;
  257.     }
  258.     pbp->cnt = 1 ;
  259.     *pbp->data = PID_NETROM ;
  260.  
  261.     /* now format network header */
  262.     if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
  263.         free_p(pbp) ;
  264.         free_p(bp) ;
  265.         return ;
  266.     }
  267.  
  268.     append(&pbp,hbp) ;        /* append header to pid */
  269.     append(&pbp,bp) ;        /* append data to header */
  270.     send_ax25(axp,pbp,-1) ;    /* pass it off to ax25 code */
  271. }
  272.     
  273.  
  274. /* Perform a nodes broadcast on interface # ifno in the net/rom
  275.  * interface table.
  276.  */
  277.  
  278. nr_bcnodes(ifno)
  279. unsigned ifno ;
  280. {
  281.     struct mbuf *hbp, *dbp, *savehdr ;
  282.     struct nrroute_tab *rp ;
  283.     struct nrnbr_tab *np ;
  284.     struct nr_bind * bp ;
  285.     struct nr3dest nrdest ;
  286.     int i, didsend = 0, numdest = 0 ;
  287.     register char *cp ;
  288.     struct iface *axif = Nrifaces[ifno].iface ;
  289.     
  290.     /* prepare the header */
  291.     if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  292.         return ;
  293.         
  294.     hbp->cnt = NR3NODEHL ;    
  295.     
  296.     *hbp->data = NR3NODESIG ;
  297.     memcpy(hbp->data+1,Nrifaces[ifno].alias,ALEN) ;
  298.  
  299.     /* Some people don't want to advertise any routes; they
  300.      * just want to be a terminal node.  In that case we just
  301.      * want to send our call and alias and be done with it.
  302.      */
  303.  
  304.     if (!Nr_verbose) {
  305.         (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  306.                          PID_NETROM, hbp) ;    /* send it */
  307.         return ;
  308.     }
  309.  
  310.     /* make a copy of the header in case we need to send more than */
  311.     /* one packet */
  312.     savehdr = copy_p(hbp,NR3NODEHL) ;
  313.  
  314.     /* now scan through the routing table, finding the best routes */
  315.     /* and their neighbors.  create destination subpackets and append */
  316.     /* them to the header */
  317.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  318.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  319.             /* look for best, non-obsolescent route */
  320.             if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  321.                 continue ;    /* no non-obsolescent routes found */
  322.             if (bp->quality == 0)    /* this is a loopback route */
  323.                 continue ;            /* we never broadcast these */
  324.             np = bp->via ;
  325.             /* insert best neighbor */
  326.             memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  327.             nrdest.neighbor.ssid = np->call[ALEN] ;
  328.             /* insert destination from route table */
  329.             nrdest.dest = rp->call ;
  330.             /* insert alias from route table */
  331.             strcpy(nrdest.alias,rp->alias) ;
  332.             /* insert quality from binding */
  333.             nrdest.quality = bp->quality ;
  334.             /* create a network format destination subpacket */
  335.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  336.                 free_p(hbp) ;    /* drop the whole idea ... */
  337.                 free_p(savehdr) ;
  338.                 return ;
  339.             }
  340.             append(&hbp,dbp) ;    /* append to header and others */
  341.             /* see if we have appended as many destinations */
  342.             /* as we can fit into a single broadcast.  If we */
  343.             /* have, go ahead and send them out. */
  344.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  345.                 didsend = 1 ;    /* indicate that we did broadcast */
  346.                 numdest = 0 ;    /* reset the destination counter */
  347.                 (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  348.                                  PID_NETROM,
  349.                                  hbp) ;    /* send it */
  350.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  351.             }
  352.         }
  353.     }
  354.  
  355.     /* Now, here is something totally weird.  If our interfaces */
  356.     /* have different callsigns than this one, advertise a very */
  357.     /* high quality route to them.  Is this a good idea?  I don't */
  358.     /* know.  However, it allows us to simulate a bunch of net/roms */
  359.     /* hooked together with a diode matrix coupler. */
  360.     for (i = 0 ; i < Nr_numiface ; i++) {
  361.         if (i == ifno)
  362.             continue ;        /* don't bother with ours */
  363.         cp = Nrifaces[i].iface->hwaddr ;
  364.         if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
  365.             /* both destination and neighbor address */
  366.             memcpy(&nrdest.dest,cp,AXALEN) ;
  367.             memcpy(&nrdest.neighbor,cp,AXALEN) ;
  368.             /* alias of the interface */
  369.             strcpy(nrdest.alias,Nrifaces[i].alias) ;
  370.             /* and the very highest quality */
  371.             nrdest.quality = 255 ;
  372.             /* create a network format destination subpacket */
  373.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  374.                 free_p(hbp) ;    /* drop the whole idea ... */
  375.                 free_p(savehdr) ;
  376.                 return ;
  377.             }
  378.             append(&hbp,dbp) ;    /* append to header and others */
  379.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  380.                 didsend = 1 ;    /* indicate that we did broadcast */
  381.                 numdest = 0 ;    /* reset the destination counter */
  382.                 (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  383.                                  PID_NETROM,
  384.                                  hbp) ;    /* send it */
  385.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  386.             }
  387.         }
  388.     }
  389.             
  390.     /* If we have a partly filled packet left over, or we never */
  391.     /* sent one at all, we broadcast: */
  392.     if (!didsend || numdest > 0)
  393.         (*axif->output)(axif, (char *)&Nr_nodebc, axif->hwaddr,
  394.                         PID_NETROM, hbp) ;
  395.  
  396.     free_p(savehdr) ;    /* free the header copy */
  397. }
  398.  
  399.  
  400. /* initialize fake arp entry for netrom */
  401. nr3arp()
  402. {
  403.  
  404.     arp_init(ARP_NETROM,AXALEN,0,0,0,NULLCHAR,psax25,setpath) ;
  405. }
  406.  
  407. /* attach the net/rom interface.  no parms for now. */
  408. nr_attach(argc,argv)
  409. int argc ;
  410. char *argv[] ;
  411. {
  412.     if (Nr_iface != (struct iface *)0) {
  413.         printf("netrom interface already attached\n") ;
  414.         return -1 ;
  415.     }
  416.  
  417.     nr3arp() ;
  418.     
  419.     Nr_iface = (struct iface *)calloc(1,sizeof(struct iface)) ;
  420.     Nr_iface->name = "netrom" ;
  421.     Nr_iface->mtu = NR4MAXINFO ;
  422.     Nr_iface->send = nr_send ;
  423.     Nr_iface->next = Ifaces ;
  424.     Ifaces = Nr_iface ;
  425.     return 0 ;
  426. }
  427.  
  428. /* This function checks an ax.25 address and interface number against
  429.  * the filter table and mode, and returns 1 if the address is to be
  430.  * accepted, and 0 if it is to be filtered out.
  431.  */
  432. static int
  433. accept_bc(addr,ifnum)
  434. struct ax25_addr *addr ;
  435. unsigned ifnum ;
  436. {
  437.     struct nrnf_tab *fp ;
  438.  
  439.     if (Nr_nfmode == NRNF_NOFILTER)        /* no filtering in effect */
  440.         return 1 ;
  441.  
  442.     fp = find_nrnf(addr,ifnum) ;        /* look it up */
  443.     
  444.     if ((fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
  445.         || (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT))
  446.         return 1 ;
  447.     else
  448.         return 0 ;
  449. }
  450.  
  451.  
  452. /* receive and process node broadcasts. */
  453. nr_nodercv(iface,source,bp)
  454. struct iface *iface ;
  455. struct ax25_addr *source ;
  456. struct mbuf *bp ;
  457. {
  458.     register int ifnum ;
  459.     char bcalias[7] ;
  460.     struct nr3dest ds ;
  461.     char sbuf[AXALEN*3] ;
  462.     
  463.     /* First, see if this is even a net/rom interface: */
  464.     for (ifnum = 0 ; ifnum < Nr_numiface ; ifnum++)
  465.         if (iface == Nrifaces[ifnum].iface)
  466.             break ;
  467.             
  468.     if (ifnum == Nr_numiface) {    /* not in the interface table */
  469.         free_p(bp) ;
  470.         return ;
  471.     }
  472.  
  473.     if (!accept_bc(source,ifnum)) {    /* check against filter */
  474.         free_p(bp) ;
  475.         return ;
  476.     }
  477.     
  478.     /* See if it has a routing broadcast signature: */
  479.     if (uchar(pullchar(&bp)) != NR3NODESIG) {
  480.         free_p(bp) ;
  481.         return ;
  482.     }
  483.  
  484.     /* now try to get the alias */
  485.     if (pullup(&bp,bcalias,ALEN) < ALEN) {
  486.         free_p(bp) ;
  487.         return ;
  488.     }
  489.  
  490.     bcalias[ALEN] = '\0' ;        /* null terminate */
  491.  
  492.     /* copy source address and convert to arp format */
  493.     memcpy(sbuf,source->call,ALEN) ;
  494.     sbuf[ALEN] = (source->ssid | E) ;    /* terminate */
  495.     
  496.     /* enter the neighbor into our routing table */
  497.     if (nr_routeadd(bcalias,source,ifnum,Nrifaces[ifnum].quality,
  498.                     sbuf, 0, 0) == -1) {
  499.         free_p(bp) ;
  500.         return ;
  501.     }
  502.     
  503.     /* we've digested the header; now digest the actual */
  504.     /* routing information */
  505.     while (ntohnrdest(&ds,&bp) != -1) {
  506.         /* ignore routes to me! */
  507.         if (ismycall(&ds.dest))
  508.             continue ;
  509.         /* ignore routes below the minimum quality threshhold */
  510.         if (ds.quality < Nr_autofloor)
  511.             continue ;
  512.         /* set loopback paths to 0 quality */
  513.         if (ismycall(&ds.neighbor))
  514.             ds.quality = 0 ;
  515.         else
  516.             ds.quality = ((ds.quality * Nrifaces[ifnum].quality + 128)
  517.                           / 256) & 0xff ;
  518.         if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
  519.             == -1)
  520.             break ;
  521.     }
  522.             
  523.     free_p(bp) ;    /* This will free the mbuf if anything fails above */
  524. }
  525.  
  526.  
  527. /* The following are utilities for manipulating the routing table */
  528.  
  529. /* hash function for callsigns.  Look familiar? */
  530. int16
  531. nrhash(s)
  532. struct ax25_addr *s ;
  533. {
  534.     register char x ;
  535.     register int i ;
  536.     register char *cp ;
  537.  
  538.     x = 0 ;
  539.     cp = s->call ;
  540.     for (i = ALEN ; i !=0 ; i--)
  541.         x ^= *cp++ & 0xfe ;
  542.     x ^= s->ssid & SSID ;
  543.     return uchar(x) % NRNUMCHAINS ;
  544. }
  545.  
  546. /* Find a neighbor table entry.  Neighbors are determined by
  547.  * their callsign and the interface number.  This takes care
  548.  * of the case where the same switch or hosts uses the same
  549.  * callsign on two different channels.  This isn't done by
  550.  * net/rom, but it might be done by stations running *our*
  551.  * software.
  552.  */
  553. struct nrnbr_tab *
  554. find_nrnbr(addr,ifnum)
  555. register struct ax25_addr *addr ;
  556. unsigned ifnum ;
  557. {
  558.     int16 hashval ;
  559.     register struct nrnbr_tab *np ;
  560.     char i_state ;
  561.     struct ax25_addr ncall ;
  562.  
  563.     /* Find appropriate hash chain */
  564.     hashval = nrhash(addr) ;
  565.  
  566.     /* search hash chain */
  567.     i_state = dirps() ;
  568.     for (np = Nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  569.         memcpy(ncall.call,np->call,ALEN) ;    /* convert first in */
  570.         ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  571.         if (addreq(&ncall,addr) && np->iface == ifnum) {
  572.             restore(i_state) ;
  573.             return np ;
  574.         }
  575.     }
  576.     restore(i_state) ;
  577.     return NULLNTAB ;
  578. }
  579.  
  580.  
  581. /* Find a route table entry */
  582. struct nrroute_tab *
  583. find_nrroute(addr)
  584. register struct ax25_addr *addr ;
  585. {
  586.     int16 hashval ;
  587.     register struct nrroute_tab *rp ;
  588.     char i_state ;
  589.  
  590.     /* Find appropriate hash chain */
  591.     hashval = nrhash(addr) ;
  592.  
  593.     /* search hash chain */
  594.     i_state = dirps() ;
  595.     for (rp = Nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  596.         if (addreq(&rp->call,addr)) {
  597.             restore(i_state) ;
  598.             return rp ;
  599.         }
  600.     }
  601.     restore(i_state) ;
  602.     return NULLNRRTAB ;
  603. }
  604.  
  605.  
  606. /* Find a binding in a list by its neighbor structure's address */
  607. struct nr_bind *
  608. find_binding(list,neighbor)
  609. struct nr_bind *list ;
  610. register struct nrnbr_tab *neighbor ;
  611. {
  612.     register struct nr_bind *bp ;
  613.  
  614.     for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  615.         if (bp->via == neighbor)
  616.             return bp ;
  617.  
  618.     return NULLNRBIND ;
  619. }
  620.  
  621. /* Find the worst quality non-permanent binding in a list */
  622. static
  623. struct nr_bind *
  624. find_worst(list)
  625. struct nr_bind *list ;
  626. {
  627.     register struct nr_bind *bp ;
  628.     struct nr_bind *worst = NULLNRBIND ;
  629.     unsigned minqual = 1000 ;     /* infinity */
  630.  
  631.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  632.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  633.             worst = bp ;
  634.             minqual = bp->quality ;
  635.         }
  636.  
  637.     return worst ;
  638. }
  639.  
  640. /* Find the best binding of any sort in a list.  If obso is 1,
  641.  * include entries below the obsolescence threshhold in the
  642.  * search (used when this is called for routing broadcasts).
  643.  * If it is 0, routes below the threshhold are treated as
  644.  * though they don't exist.
  645.  */
  646. static
  647. struct nr_bind *
  648. find_best(list,obso)
  649. struct nr_bind *list ;
  650. unsigned obso ;
  651. {
  652.     register struct nr_bind *bp ;
  653.     struct nr_bind *best = NULLNRBIND ;
  654.     int maxqual = -1 ;    /* negative infinity */
  655.  
  656.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  657.         if ((int)bp->quality > maxqual)
  658.             if (obso || bp->obsocnt >= Obso_minbc) {
  659.                 best = bp ;
  660.                 maxqual = bp->quality ;
  661.             }
  662.  
  663.     return best ;
  664. }
  665.  
  666. /* Add a route to the net/rom routing table */
  667. nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
  668. char *alias ;                /* net/rom node alias, blank-padded and */
  669.                             /* null-terminated */
  670. struct ax25_addr *dest ;    /* destination node callsign */
  671. unsigned ifnum ;            /* net/rom interface number */
  672. unsigned quality ;            /* route quality */
  673. char *neighbor ;            /* neighbor node + 2 digis (max) in arp format */
  674. unsigned permanent ;        /* 1 if route is permanent (hand-entered) */
  675. unsigned record ;            /* 1 if route is a "record route" */
  676. {
  677.     struct nrroute_tab *rp ;
  678.     struct nr_bind *bp ;
  679.     struct nrnbr_tab *np ;
  680.     int16 rhash, nhash ;
  681.     struct ax25_addr ncall ;
  682.  
  683.     /* See if a routing table entry exists for this destination */
  684.     if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  685.         if ((rp =
  686.              (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  687.             == NULLNRRTAB)
  688.             return -1 ;
  689.         else {            /* create a new route table entry */
  690.             strncpy(rp->alias,alias,6) ;
  691.             rp->call = *dest ;
  692.             rhash = nrhash(dest) ;
  693.             rp->next = Nrroute_tab[rhash] ;
  694.             if (rp->next != NULLNRRTAB)
  695.                 rp->next->prev = rp ;
  696.             Nrroute_tab[rhash] = rp ;    /* link at head of hash chain */
  697.         }
  698.      } else if (!record) {
  699.          strncpy(rp->alias,alias,6) ;    /* update the alias */
  700.     }
  701.  
  702.     /* See if an entry exists for this neighbor */
  703.     memcpy(ncall.call,neighbor,ALEN) ;    /* no digis included */
  704.     ncall.ssid = neighbor[ALEN] ;
  705.     if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  706.         if ((np =
  707.              (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  708.              == NULLNTAB) {
  709.             if (rp->num_routes == 0) {    /* we just added to table */
  710.                 Nrroute_tab[rhash] = rp->next ;
  711.                 free(rp) ;                /* so get rid of it */
  712.             }
  713.             return -1 ;
  714.         }
  715.         else {        /* create a new neighbor entry */
  716.             memcpy(np->call,neighbor,3 * AXALEN) ;
  717.             np->iface = ifnum ;
  718.             nhash = nrhash(&ncall) ;
  719.             np->next = Nrnbr_tab[nhash] ;
  720.             if (np->next != NULLNTAB)
  721.                 np->next->prev = np ;
  722.             Nrnbr_tab[nhash] = np ;
  723.         }
  724.     }
  725.     else if (permanent) {        /* force this path to the neighbor */
  726.         memcpy(np->call,neighbor,3 * AXALEN) ;
  727.     }
  728.         
  729.     /* See if there is a binding between the dest and neighbor */
  730.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  731.         if ((bp =
  732.              (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  733.             == NULLNRBIND) {
  734.             if (rp->num_routes == 0) {    /* we just added to table */
  735.                 Nrroute_tab[rhash] = rp->next ;
  736.                 free(rp) ;                /* so get rid of it */
  737.             }
  738.             if (np->refcnt == 0) {        /* we just added it */
  739.                 Nrnbr_tab[nhash] = np->next ;
  740.                 free(np) ;
  741.             }
  742.             return -1 ;
  743.         }
  744.         else {        /* create a new binding and link it in */
  745.             bp->via = np ;    /* goes via this neighbor */
  746.             bp->next = rp->routes ;    /* link into binding chain */
  747.             if (bp->next != NULLNRBIND)
  748.                 bp->next->prev = bp ;
  749.             rp->routes = bp ;
  750.             rp->num_routes++ ;    /* bump route count */
  751.             np->refcnt++ ;        /* bump neighbor ref count */
  752.             bp->quality = quality ;
  753.             bp->obsocnt = Obso_init ;    /* use initial value */
  754.             if (permanent)
  755.                 bp->flags |= NRB_PERMANENT ;
  756.             else if (record)    /* notice permanent overrides record! */
  757.                 bp->flags |= NRB_RECORDED ;
  758.         }
  759.      } else {
  760.          if (permanent) {    /* permanent request trumps all */
  761.              bp->quality = quality ;
  762.              bp->obsocnt = Obso_init ;
  763.              bp->flags |= NRB_PERMANENT ;
  764.              bp->flags &= ~NRB_RECORDED ;    /* perm is not recorded */
  765.          } else if (!(bp->flags & NRB_PERMANENT)) {    /* not permanent */
  766.              if (record) {    /* came from nr_route */
  767.                  if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
  768.                      bp->quality = quality ;
  769.                      bp->obsocnt = Obso_init ; /* freshen recorded routes */
  770.                  }
  771.              } else {        /* came from a routing broadcast */
  772.                  bp->quality = quality ;
  773.                  bp->obsocnt = Obso_init ;
  774.                  bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
  775.              }
  776.          }
  777.     }
  778.  
  779.     /* Now, check to see if we have too many bindings, and drop */
  780.     /* the worst if we do */
  781.     if (rp->num_routes > Nr_maxroutes) {
  782.         /* since find_worst never returns permanent entries, the */
  783.         /* limitation on number of routes is circumvented for    */
  784.         /* permanent routes */
  785.         if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  786.             memcpy(ncall.call,bp->via->call,ALEN) ;
  787.             ncall.ssid = bp->via->call[ALEN] ;
  788.             nr_routedrop(dest,&ncall,bp->via->iface) ;
  789.         }
  790.     }
  791.  
  792.     return 0 ;
  793. }
  794.  
  795.  
  796. /* Drop a route to dest via neighbor */
  797. nr_routedrop(dest,neighbor,ifnum)
  798. struct ax25_addr *dest, *neighbor ;
  799. unsigned ifnum ;
  800. {
  801.     register struct nrroute_tab *rp ;
  802.     register struct nrnbr_tab *np ;
  803.     register struct nr_bind *bp ;
  804.  
  805.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  806.         return -1 ;
  807.  
  808.     if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  809.         return -1 ;
  810.  
  811.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  812.         return -1 ;
  813.  
  814.     /* drop the binding first */
  815.     if (bp->next != NULLNRBIND)
  816.         bp->next->prev = bp->prev ;
  817.     if (bp->prev != NULLNRBIND)
  818.         bp->prev->next = bp->next ;
  819.     else
  820.         rp->routes = bp->next ;
  821.  
  822.     free(bp) ;
  823.     rp->num_routes-- ;        /* decrement the number of bindings */
  824.     np->refcnt-- ;            /* and the number of neighbor references */
  825.     
  826.     /* now see if we should drop the route table entry */
  827.     if (rp->num_routes == 0) {
  828.         if (rp->next != NULLNRRTAB)
  829.             rp->next->prev = rp->prev ;
  830.         if (rp->prev != NULLNRRTAB)
  831.             rp->prev->next = rp->next ;
  832.         else
  833.             Nrroute_tab[nrhash(dest)] = rp->next ;
  834.  
  835.         free(rp) ;
  836.     }
  837.  
  838.     /* and check to see if this neighbor can be dropped */
  839.     if (np->refcnt == 0) {
  840.         if (np->next != NULLNTAB)
  841.             np->next->prev = np->prev ;
  842.         if (np->prev != NULLNTAB)
  843.             np->prev->next = np->next ;
  844.         else
  845.             Nrnbr_tab[nrhash(neighbor)] = np->next ;
  846.  
  847.         free(np) ;
  848.     }
  849.     
  850.     return 0 ;
  851. }
  852.  
  853. /* Find the best neighbor for destination dest, in arp format */
  854. char *
  855. nr_getroute(dest)
  856. struct ax25_addr *dest ;
  857. {
  858.     register struct nrroute_tab *rp ;
  859.     register struct nr_bind *bp ;
  860.  
  861.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  862.         return NULLCHAR ;
  863.  
  864.     if ((bp = find_best(rp->routes)) == NULLNRBIND)    /* shouldn't happen! */
  865.         return NULLCHAR ;
  866.  
  867.     return bp->via->call ;
  868. }
  869.  
  870. /* Find an entry in the filter table */
  871. struct nrnf_tab *
  872. find_nrnf(addr,ifnum)
  873. register struct ax25_addr *addr ;
  874. unsigned ifnum ;
  875. {
  876.     int16 hashval ;
  877.     register struct nrnf_tab *fp ;
  878.  
  879.     /* Find appropriate hash chain */
  880.     hashval = nrhash(addr) ;
  881.  
  882.     /* search hash chain */
  883.     for (fp = Nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  884.         if (addreq(&fp->neighbor,addr) && fp->iface == ifnum) {
  885.             return fp ;
  886.         }
  887.     }
  888.  
  889.     return NULLNRNFTAB ;
  890. }
  891.  
  892. /* Add an entry to the filter table.  Return 0 on success,
  893.  * -1 on failure
  894.  */
  895. int
  896. nr_nfadd(addr,ifnum)
  897. struct ax25_addr *addr ;
  898. unsigned ifnum ;
  899. {
  900.     struct nrnf_tab *fp ;
  901.     int16 hashval ;
  902.     
  903.     if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  904.         return 0 ;    /* already there; it's a no-op */
  905.  
  906.     if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  907.         == NULLNRNFTAB)
  908.         return -1 ;    /* no storage */
  909.  
  910.     hashval = nrhash(addr) ;
  911.     fp->neighbor = *addr ;
  912.     fp->iface = ifnum ;
  913.     fp->next = Nrnf_tab[hashval] ;
  914.     if (fp->next != NULLNRNFTAB)
  915.         fp->next->prev = fp ;
  916.     Nrnf_tab[hashval] = fp ;
  917.  
  918.     return 0 ;
  919. }
  920.  
  921. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  922.  * on failure.
  923.  */
  924. int
  925. nr_nfdrop(addr,ifnum)
  926. struct ax25_addr *addr ;
  927. unsigned ifnum ;
  928. {
  929.     struct nrnf_tab *fp ;
  930.  
  931.     if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  932.         return -1 ;    /* not in the table */
  933.  
  934.     if (fp->next != NULLNRNFTAB)
  935.         fp->next->prev = fp->prev ;
  936.     if (fp->prev != NULLNRNFTAB)
  937.         fp->prev->next = fp->next ;
  938.     else
  939.         Nrnf_tab[nrhash(addr)] = fp->next ;
  940.  
  941.     free(fp) ;
  942.  
  943.     return 0 ;
  944. }
  945.